// You will build this in project part B - this is merely a
// stub that does nothing but integrate into the stack

// For project parts A and B, an appropriate binary will be 
// copied over as part of the build process



#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>


#include <iostream>
#include <list>
#include "Minet.h"
#include "tcpstate.h"
using namespace std;

static const int F_SYN = 1;
static const int F_ACK = 2;
static const int F_SYNACK = 3;
static const int F_PSHACK = 4;
static const int F_FIN = 5;
static const int F_FINACK = 6;
static const int F_RST = 7;
static bool bFirstSend = true;

void handle_mux(const MinetHandle &mux, const MinetHandle &sock, ConnectionList<TCPState> &clist);
void handle_sock(const MinetHandle &mux, const MinetHandle &sock, ConnectionList<TCPState> &clist);
void handle_timeout(const MinetHandle &mux, const MinetHandle &sock, ConnectionList<TCPState> &clist);
void createIPPacket(Packet &pack, ConnectionToStateMapping<TCPState> &a_mapping, int size_of_data, int header,
		    bool bCustomizedSeq = false, int my_seq=0);

int main(int argc, char * argv[]) {
  MinetHandle mux;
  MinetHandle sock;
    
  ConnectionList<TCPState> clist;

  MinetInit(MINET_TCP_MODULE);

  mux = MinetIsModuleInConfig(MINET_IP_MUX) ?  
    MinetConnect(MINET_IP_MUX) : 
    MINET_NOHANDLE;
    
  sock = MinetIsModuleInConfig(MINET_SOCK_MODULE) ? 
    MinetAccept(MINET_SOCK_MODULE) : 
    MINET_NOHANDLE;

  if ( (mux == MINET_NOHANDLE) && 
       (MinetIsModuleInConfig(MINET_IP_MUX)) ) {

    MinetSendToMonitor(MinetMonitoringEvent("Can't connect to ip_mux"));

    return -1;
  }

  if ( (sock == MINET_NOHANDLE) && 
       (MinetIsModuleInConfig(MINET_SOCK_MODULE)) ) {

    MinetSendToMonitor(MinetMonitoringEvent("Can't accept from sock_module"));

    return -1;
  }
    
  cerr << "tcp_module STUB VERSION handling tcp traffic.......\n";

  MinetSendToMonitor(MinetMonitoringEvent("tcp_module STUB VERSION handling tcp traffic........"));

  MinetEvent event;
  double timeout = 1;

  while (MinetGetNextEvent(event, timeout) == 0) {
    
    if ((event.eventtype == MinetEvent::Dataflow) && 
	(event.direction == MinetEvent::IN)) {
      if (event.handle == mux) {
	// ip packet has arrived!
	handle_mux(mux, sock, clist);
      }

      if (event.handle == sock) {
	// socket request or response has arrived
	handle_sock(mux, sock, clist);
      }
      cout<<endl<<endl;
    }

    if (event.eventtype == MinetEvent::Timeout) {
      // timeout ! probably need to resend some packets
      handle_timeout(mux,sock,clist);
    }

  }

  MinetDeinit();

  return 0;
}

void handle_mux(const MinetHandle &mux, const MinetHandle &sock, ConnectionList<TCPState> &clist){
  // handle-mux represents the receiver!
  cout << "new ip packet arrived" << endl;
  Packet packet;
  Packet outgoing_packet;
  bool check_sum;
  TCPHeader tcp;
  IPHeader ip;
  Connection c;
	
  unsigned int ack;
  unsigned int seq;
  //unsigned int status;
  SockRequestResponse repl, req;
  //unsigned int request = 0;
  unsigned short length;
  unsigned char tcph_len, iph_len,flags;
  unsigned short window_size, urgent_p;
  //bool ordering;
	
  Buffer buffer;
	
  MinetReceive(mux, packet);

  // Extract and find header from payload
  //packet.ExtractHeaderFromPayload<TCPHeader>(8); 
  packet.ExtractHeaderFromPayload<TCPHeader>(TCPHeader::EstimateTCPHeaderLength(packet));
  tcp = packet.FindHeader(Headers::TCPHeader);

  // Extract IP Header
  ip = packet.FindHeader(Headers::IPHeader);

  // Extract IP Header Data 
  // note that this is flipped around because "source" is interepreted as "this machine"
  ip.GetDestIP(c.src);
  ip.GetSourceIP(c.dest);
  ip.GetProtocol(c.protocol);

  // Extract TCP Header Data FIXME: may need to move back into main loop...?
  tcp.GetSourcePort(c.destport);	
  tcp.GetDestPort(c.srcport);
  tcp.GetSeqNum(seq);
  tcp.GetAckNum(ack);
  tcp.GetFlags(flags);
  tcp.GetWinSize(window_size);	
  tcp.GetUrgentPtr(urgent_p);
	
  //Get the data!
	
  ip.GetTotalLength(length);
  ip.GetHeaderLength(iph_len);
  iph_len<<=2;
  tcp.GetHeaderLen(tcph_len);
  tcph_len<<=2;
  length = length - tcph_len - iph_len;
  cout<<"ip len = "<<length<<endl;
  buffer = packet.GetPayload().ExtractFront(length);

  // Verify checksum
  check_sum = tcp.IsCorrectChecksum(packet);

  ConnectionList<TCPState>::iterator cs = clist.FindMatching(c);
  printf("seq %d, ack %d\n",seq,ack);
  //Connection exists
  if (cs != clist.end()){
    cout<<"conn exist"<<endl;
    cout<<c<<endl;
    unsigned int currentState; //This is the current state of the tcp connection.
    currentState = cs->state.GetState();
    cout<<"state = "<<currentState<<endl;
    cs->state.rwnd = window_size;//update other's recv window size
    if(window_size <= cs->state.GetN()) {//if other's window size is less than our sending window size
      cs->state.N = window_size/TCP_MAXIMUM_SEGMENT_SIZE*TCP_MAXIMUM_SEGMENT_SIZE;
    }
    //Main handling functions
    switch(currentState){
      
    case CLOSED:
      //closed.
      cout<<"closed"<<endl;
      break;
    case LISTEN:
      {
	cout<<"listen"<<endl;
	//listen
	if(IS_SYN(flags)){
	  (*cs).state.SetState(SYN_RCVD);
	  (*cs).state.last_acked = (*cs).state.last_sent-1;
	  (*cs).state.SetLastRecvd(seq+1);
	  (*cs).bTmrActive = true;//activate time out
	  (*cs).timeout=Time() + 0.2;//set time out period
	  (*cs).connection = c;//update connection
	  createIPPacket(outgoing_packet, *cs, 0, F_SYNACK);//create syn ack packet
	  MinetSend(mux, outgoing_packet);
	  if(bFirstSend) {
	    sleep(2);
	    MinetSend(mux, outgoing_packet);
	    bFirstSend = false;
	  }
	  break;
	}
	else if(IS_FIN(flags)) {
	  createIPPacket(outgoing_packet, *cs, 0, 6);
	  MinetSend(mux, outgoing_packet);
	}
	break;
      }
    case SYN_RCVD:
      {
	cout<<"syn_rcvd"<<endl;
	//syn_rcvd
	if(IS_ACK(flags)){
	  if(cs->state.GetLastSent()+1 == ack){
	    cout<<"established!"<<endl;
	    cs->state.SetState(ESTABLISHED);
	    cs->state.SetLastAcked(ack);
	    cs->state.SetSendRwnd(window_size); 
	    cs->bTmrActive = false;
	    repl.type = WRITE;
	    repl.connection = c;
	    repl.error = EOK;
	    repl.bytes = 0;
	    MinetSend(sock, repl);
	  }
	}
      }
      break;
    case SYN_SENT:
      {
	cout<<"syn sent"<<endl;
	//SYN_SENT
	if(IS_SYN(flags) && IS_ACK(flags)){
	  cs->state.SetLastRecvd(seq+1);
	  cout<<"set acked "<<((cs->state.SetLastAcked(ack))?"yes":"no")<<endl;
	  cs->state.SetSendRwnd(window_size);

	  createIPPacket(outgoing_packet, *cs, 0, F_ACK);//create an ack packet
	  MinetSend(mux, outgoing_packet);
	  cs->state.SetState(ESTABLISHED);
	  cs->bTmrActive = false;//turn syn packet retransmission timer off
	  SockRequestResponse write (WRITE, cs->connection, buffer, 0, EOK);
	  MinetSend(sock, write);
	  
	  MinetSend(sock, write);
	} else if (IS_SYN(flags)){
	  cs->state.SetLastRecvd(seq);
	  createIPPacket(outgoing_packet, *cs, 0, 2);//create an ack packet
	  MinetSend(mux, outgoing_packet);
	  cs->state.SetState(SYN_RCVD);
	  cs->state.SetLastSent(cs->state.GetLastSent()+1);
	}
	else if(IS_FIN(flags) && IS_ACK(flags)) {
	  // Update state given FIN received					
	  cs->state.SetLastRecvd(seq+1);
					
	  // Update seq & ack numbers, tbd how
	  createIPPacket(outgoing_packet, *cs, 0, 6);
	  MinetSend(mux, outgoing_packet);

	  // Update state
	  cs->state.SetState(CLOSE_WAIT);
				
	  // Notify socket of close
	  //SocketRequestResponse close_reply(CLOSE, connstate.connection, buffer, 0, EOK);
	  repl.connection=req.connection;
	  repl.type=STATUS;
	  if (cs==clist.end()) {
	    repl.error=ENOMATCH;
	  } else {
	    repl.error=EOK;
	    clist.erase(cs);
	  }
	  MinetSend(sock,repl);
	}
	break;
      }
    case SYN_SENT1: //SYN_SENT1
      {
	cout<<"syn_sent1"<<endl;
	break;
      }
    case ESTABLISHED:
      {
	cout<<"established"<<endl;
	//Established
	if (length!=0) {//we have a data packet
	  // Check sequence number and checksum
	  if(seq == cs->state.GetLastRecvd() && check_sum) {
	    cout<<"recv data good"<<endl;
	    cs->state.SetLastRecvd(seq+length);
	    cout<<"set acked "<<((cs->state.SetLastAcked(ack))?"yes":"no")<<endl;
	    if(cs->state.GetRwnd() >= length) {//there is enough space in receive buffer
	      cs->state.RecvBuffer.AddBack(buffer);	      
	      // Write to socket
	      SockRequestResponse write (WRITE, cs->connection, cs->state.RecvBuffer, 
					 cs->state.RecvBuffer.GetSize(), EOK);
	      MinetSend(sock,write);
	    }
	    else {//not enough space in recv buffer
	      cs->state.SetLastRecvd(seq);
	    }
	    // Make and send an ACK Packet, assuming ordering
	    createIPPacket(outgoing_packet, *cs, 0, F_ACK);//create ack packet
	    MinetSend(mux, outgoing_packet);
				
	  } else  {//out of order or corrupted packet
	    // Unexpected seq: create ACK Packet
	    createIPPacket(outgoing_packet, *cs, 0, F_ACK);
	    MinetSend(mux,outgoing_packet);
	  }

	} else if (IS_FIN(flags)) {				
	  cs->state.SetLastRecvd(seq+1);

	  createIPPacket(outgoing_packet, *cs, 0, F_FINACK);//create fin ack packet
	  MinetSend(mux, outgoing_packet);

	  // Update state
	  cs->state.SetState(LAST_ACK);
	  

	} else if (IS_ACK(flags)) {
	  cout<<"only ack ";
	  if (ack <= cs->state.GetLastAcked()+1) {//duplicate ack
	    //it will time out	
	    cout<<"duplicate ack"<<ack<<", last acked "<<cs->state.GetLastAcked()+1;
	  }
	  else {//update tcp state
	    cs->state.SetLastRecvd((unsigned int)seq);
	    cs->state.SetLastAcked(ack);
	    if(cs->state.GetLastAcked() == cs->state.GetLastSent()-1) {
	      cout<<"timer off ";
	      cs->bTmrActive = false;//turn off timer
	    }
	    else {//there still data not coming
	      cout<<"new timer ";
	      cs->bTmrActive = true;
	      cs->timeout = Time()+5;//new 5 second timer
	      cs->state.tmrTries = 3;//resend the window 3 times if no ack coming
	    }
	  }
	  cout<<endl;
	} 				

	break;	
      }
    case LAST_ACK: //waiting for last ack
      if(IS_ACK(flags)) {
	cout<<"last ack coming"<<endl;
	repl.connection = c;
	repl.type = WRITE;
	repl.bytes = 0;
	if (cs==clist.end()) {
	  repl.error=ENOMATCH;
	} else {
	  cout<<"conn ok"<<endl;
	  repl.error=EOK;
	}
	MinetSend(sock,repl);
	cs->state.SetState(CLOSED);
	clist.erase(cs);
	cout<<"send close to sock"<<endl;
      }
      break;
    case FIN_WAIT1: {
      if(IS_FIN(flags) && IS_ACK(flags)) {//send out last ack
	cs->state.SetLastRecvd(seq+1);
	cs->state.SetLastAcked(ack);
	createIPPacket(outgoing_packet, *cs, 0, F_ACK);
        MinetSend(mux,outgoing_packet);
	cs->bTmrActive = true;//turn on timer
	cs->timeout = Time()+5;//wait 5 second
	cs->state.SetState(TIME_WAIT);
      }
    }
      break;
    default:
      cout<<"default"<<endl;
      break;
    }
		
  }
  else {//connection not exist
    cout<<"conn not exist"<<endl;
    if(IS_FIN(flags)) {
      cout<<c<<endl;
      TCPState a_new_state(1, CLOSED, 3);
      a_new_state.SetLastRecvd(seq);
      a_new_state.last_acked = (ack-1);
      ConnectionToStateMapping<TCPState> a_new_map(c, Time(), a_new_state, false);
      createIPPacket(outgoing_packet, a_new_map, 0, F_ACK);
      MinetSend(mux, outgoing_packet);
      bFirstSend = false;
      cout<<"fin ack sent"<<endl;
    }
    else if(IS_SYN(flags)) {
      cout<<"syn"<<endl;
    }
  }
	
	
}

void handle_sock(const MinetHandle &mux, const MinetHandle &sock, ConnectionList<TCPState> &clist)
{
  // GBN Sender Data
  // Packet and Socket info
  Packet outgoing_packet;
  SockRequestResponse reply;
  SockRequestResponse req;
  Buffer buff;
  cout<<"handle sock"<<endl;
  //Receive sock request here.
  MinetReceive(sock, req);
  ConnectionList<TCPState>::iterator cs = clist.FindMatching(req.connection);
  //Handle new connections here.
  cout<<req<<endl;
  if(cs == clist.end()){
    cout<<"conn not exist: "<<endl;
    switch(req.type) {
    case CONNECT:{
      cout<<"Connect event"<<endl;
      TCPState a_new_state(1, SYN_SENT, 3);//after send out syn packet, next state is SYN_SENT
      ConnectionToStateMapping<TCPState> a_new_map(req.connection, Time()+.2, a_new_state, true);
      createIPPacket(outgoing_packet, a_new_map, 0, F_SYN);//create syn packet
      MinetSend(mux, outgoing_packet);
      if(bFirstSend) {
	sleep(2);
	MinetSend(mux, outgoing_packet);
	bFirstSend = false;
      }
      a_new_map.state.SetLastSent(a_new_map.state.GetLastSent()+1);
      clist.push_back(a_new_map);
      reply.type = STATUS;
      reply.connection = req.connection;
      reply.bytes = 0;
      reply.error = EOK;
      MinetSend(sock, reply);
    }
      break;
    case ACCEPT:{
      cout<<"accept: "<<endl;
      TCPState a_new_state(1, LISTEN, 3);
      ConnectionToStateMapping<TCPState> a_new_map(req.connection, Time(), a_new_state, false);
      a_new_map.bTmrActive = false;
      clist.push_back(a_new_map);
      reply.type = STATUS;
      reply.connection = req.connection;
      reply.bytes = 0;
      reply.error = EOK;
      MinetSend(sock, reply);
    }
      break;
    case STATUS: {
      cout<<"status: "<<endl;
    }
      break;
    case WRITE: {
      reply.type = STATUS;
      reply.connection = req.connection;
      reply.bytes = 0;
      reply.error = ENOMATCH;
      MinetSend(sock, reply);
    }
      break;
    case FORWARD: {

    }
      break;
    case CLOSE: {
      reply.type = STATUS;
      reply.connection = req.connection;
      reply.bytes = 0;
      reply.error = ENOMATCH;
      MinetSend(sock, reply);
    }
      break;
    default:
      break;
    }
  }
  //This is an existing connection.
  else {
    cout<<"conn exist ";
    int state = cs->state.GetState();
    cout<<(*cs)<<endl;
    Buffer buff;
    switch (req.type) {
    case CONNECT:{
      cout<<"Connect event"<<endl;
      
    }
      break;
    case ACCEPT:{
      cout<<"accept event"<<endl;    
    }
      break;
    case STATUS: {
      cout<<"status ";
      if(ESTABLISHED == state) {//status in response to write event
	unsigned datasend = req.bytes;//number of bytes send
	cs->state.RecvBuffer.Erase(0,datasend);
	if(0 != cs->state.RecvBuffer.GetSize()) {//data did not write completely
	  cout<<"data not send completely"<<endl;
	  SockRequestResponse write (WRITE, cs->connection, cs->state.RecvBuffer, cs->state.RecvBuffer.GetSize(), EOK);
	  MinetSend(sock,write);
	}
      }
      cout<<endl;
    }
      break;
    case WRITE: {
      cout<<"write ";
      if(state == ESTABLISHED) {
	cout<<"established"<<endl;
	if(cs->state.SendBuffer.GetSize()+req.data.GetSize() > 
	   cs->state.TCP_BUFFER_SIZE) {//send buffer dont have enough space
	  reply.type = STATUS;
	  reply.connection = req.connection;
	  reply.bytes = 0;
	  reply.error = EBUF_SPACE;
	  MinetSend(sock, reply);
	}
	else {//enough space in sendbuffer
	  cs->state.SendBuffer.AddBack(req.data);//append new data
	}

	//flow control, wouldn't send data overflow other conns
	if(cs->state.last_sent - cs->state.last_acked < cs->state.rwnd) {
	  if(cs->state.last_sent == cs->state.last_acked) {//no data on transition
	    //activate timer
	    cs->bTmrActive = true;
	    cs->timeout = Time()+5;//expire in 5 sec
	    cs->state.tmrTries = 3;//retransmit only 3 times
	  }
	  unsigned int totalsend = 0;//total data send this time
	  Buffer buffer = cs->state.SendBuffer;//copy buffer
	  //get rid of data we already send, what left is data we haven't send
	  buffer.ExtractFront(cs->state.last_sent-cs->state.last_acked);  
	  unsigned int totaleft = buffer.GetSize();
	  
	  //int kk =0 ;//testing purpose
	  //maximum amount of data we can sent and not cause over flow
	  //Note, N is updated to be always less than rwnd
	  unsigned int MAX_SENT = cs->state.GetN()-(cs->state.last_sent-cs->state.last_acked)-
	    TCP_MAXIMUM_SEGMENT_SIZE;
	  //while we have data left to send and total data send does not exceed 
	  //our window size
	  printf("total left%d,%d, maxsent%d\n",totaleft,totalsend,MAX_SENT);
	  while(totaleft!=0 && 
		totalsend < MAX_SENT) {
	    unsigned int bytes = min(totaleft,TCP_MAXIMUM_SEGMENT_SIZE);//data we send this time
	    cout<<totalsend<<", "<<bytes<<endl;
	    outgoing_packet = buffer.Extract(0,bytes);
	    //creat packet
	    createIPPacket(outgoing_packet, *cs, bytes, F_PSHACK,true,
			   cs->state.GetLastAcked()+1+totalsend);
	    //send ip packet
	    //if(kk!=1) {//testing purpose
	    MinetSend(mux, outgoing_packet);
	    //}
	    // kk++;
	    cs->state.SetLastSent(cs->state.GetLastSent()+bytes);
	    totalsend += bytes;
	    //update totaleft
	    totaleft -= bytes;
	  }
	
	  reply.type = STATUS;
	  reply.connection = req.connection;
	  reply.bytes = totalsend;
	  reply.error = EOK;
	  MinetSend(sock, reply);
	}
	
      }
      else {
	cout<<"invalid state"<<endl;
      }
      
    }
      break;
    case FORWARD: {
      cout<<"foward do nothing"<<endl;
    }
      break;
    case CLOSE: {
      cout<<"close ";
      if(ESTABLISHED == state) {//user init the close action
	cout<<"established"<<endl;
	createIPPacket(outgoing_packet, *cs, 0, F_FIN);//create fin packet
	MinetSend(mux,outgoing_packet);
	cs->state.SetLastSent(cs->state.GetLastSent()+1);
	cs->state.SetState(FIN_WAIT1);
      }
      else if(CLOSED == state) {
	reply.type = STATUS;
	reply.connection = req.connection;
	reply.bytes = 0;
	reply.error = EOK;
	MinetSend(sock, reply);
	clist.erase(cs);	
      }
      else {
	cout<<"invalid state"<<endl;
      }
    }
      break;
    default:
      break;
    }

  }
}




void createIPPacket(Packet &packet, ConnectionToStateMapping<TCPState> &a_mapping, int size_of_data, int header,
		    bool bCustomizedSeq, int my_seq)
{
  cout<<"create new ip packet"<<endl;
  unsigned char flags = 0;

  int packet_length = size_of_data + TCP_HEADER_BASE_LENGTH + IP_HEADER_BASE_LENGTH;
  IPHeader ip;
  TCPHeader tcp;
  IPAddress source = a_mapping.connection.src;
  IPAddress destination = a_mapping.connection.dest;
  unsigned short source_port = a_mapping.connection.srcport;
  unsigned short destination_port = a_mapping.connection.destport;

  ip.SetSourceIP(source);
  ip.SetDestIP(destination);
  ip.SetTotalLength(packet_length);
  ip.SetProtocol(IP_PROTO_TCP);

  packet.PushFrontHeader(ip);
  switch (header){
  case F_SYN:
    SET_SYN(flags);
    break;

  case F_ACK:
    SET_ACK(flags);
    break;

  case F_SYNACK:
    SET_ACK(flags);
    SET_SYN(flags);
    break;
  case F_PSHACK:
    SET_PSH(flags);
    SET_ACK(flags);
    break;

  case F_FIN:
    SET_FIN(flags);
    break;

  case F_FINACK:
    SET_FIN(flags);
    SET_ACK(flags);
    break;

  case F_RST:
    SET_RST(flags);
    break;

  default:
    break;
  }
  tcp.SetSourcePort(source_port, packet);
  tcp.SetDestPort(destination_port, packet);
  tcp.SetHeaderLen(TCP_HEADER_BASE_LENGTH, packet);
  tcp.SetFlags(flags, packet);
  tcp.SetAckNum(a_mapping.state.GetLastRecvd(), packet);
  if(bCustomizedSeq) {
    tcp.SetSeqNum(a_mapping.state.GetLastSent()+1, packet);
  }
  else {
    tcp.SetSeqNum(a_mapping.state.GetLastAcked()+1, packet);
  }
  tcp.SetWinSize(a_mapping.state.GetRwnd(), packet);
  tcp.SetUrgentPtr(0, packet);
  //tcp.RecomputeChecksum(packet);
  packet.PushBackHeader(tcp);

}

void handle_timeout(const MinetHandle &mux, const MinetHandle &sock, ConnectionList<TCPState> &clist) {
  Time now;//get current time
  list<ConnectionList<TCPState>::iterator> dellist;
  for(ConnectionList<TCPState>::iterator cs = clist.begin(); cs!=clist.end(); cs++) {
    if(!cs->bTmrActive)//did not activate timer 
      continue;
    // cout<<now<<", "<<cs->timeout<<endl<<endl;
    if(now > cs->timeout || now == cs->timeout) {//a timeout occurs
      cout<<"time out"<<endl;
      switch (cs->state.GetState()) {
      case SYN_SENT: {//sent out syn waiting for synack
	if(cs->state.ExpireTimerTries()) {//we run out of tries, close the connection
	  cout<<"number of tries run out"<<endl<<endl;
	  //close the connection
	  Buffer buffer;
	  SockRequestResponse reply(WRITE, cs->connection, buffer, 0, ECONN_FAILED);//close it
	  MinetSend(sock, reply);
	  cs->bTmrActive = false;
	  cs->state.SetState(CLOSING);
	}
	else {//send syn again
	  cout<<"send out syn again"<<endl<<endl;;
	  Packet outgoing_packet;
	  createIPPacket(outgoing_packet, *cs, 0, F_SYN);//create syn packet
	  MinetSend(mux, outgoing_packet);
	  cs->timeout = now+0.2;
	}
      }
	break;
      case SYN_RCVD: {//waiting for last ack coming
	if(cs->state.ExpireTimerTries()) {//we run out of tries, close the connection
	  cout<<"number of tries run out"<<endl<<endl;
	  //close the connection
	  //Buffer buffer;
	  //SockRequestResponse reply(WRITE, cs->connection, buffer, 0, ECONN_FAILED);//close it
	  //MinetSend(sock, reply);
	  cs->bTmrActive = false;
	  cs->state.SetState(LISTEN);
	}
	else {
	  cout<<"send out syn ack again"<<endl<<endl;
	  Packet outgoing_packet;
	  createIPPacket(outgoing_packet, *cs, 0, F_SYNACK);//create syn ack packet
	  MinetSend(mux, outgoing_packet);
	  cs->timeout = now+0.2;
	}
      }
	break;
      case TIME_WAIT: {
	cout<<"time wait"<<endl;
	//close the connection
	dellist.push_back(cs);
	
      }
	break;
      case ESTABLISHED: {
	//todo
	//we have outstanding acked 
	if(cs->state.last_acked < cs->state.last_sent) {
	  if(!cs->state.ExpireTimerTries()) {
	    //activate timer
	    cs->bTmrActive = true;
	    cs->timeout = Time()+5;//expire in 5 sec
	    unsigned int totalsend = 0;//total data send this time
	    Buffer buffer = cs->state.SendBuffer;//copy buffer
	    //get rid of data we already send, what left is data we haven't send
	    buffer = buffer.ExtractFront(cs->state.last_sent-cs->state.last_acked);  
	    unsigned int totaleft = buffer.GetSize();
	    Packet outgoing_packet;
	    //maximum amount of data we can sent and not cause over flow
	    //Note, N is updated to be always <= rwnd
	    unsigned int MAX_SENT = cs->state.GetN()-(cs->state.last_sent-cs->state.last_acked)-
	      TCP_MAXIMUM_SEGMENT_SIZE;
	    cs->state.SetLastSent(cs->state.GetLastAcked());
	    //while we have data left to send and total data send does not exceed 
	    //our window size
	    while(totaleft!=0 && 
		  totalsend < MAX_SENT) {
	      unsigned int bytes = min(totaleft,TCP_MAXIMUM_SEGMENT_SIZE);//data we send this time
	      cout<<totalsend<<", "<<bytes<<endl;
	      outgoing_packet = buffer.Extract(0,bytes);
	      //creat packet
	      createIPPacket(outgoing_packet, *cs, bytes, F_PSHACK,true,
			     cs->state.GetLastAcked()+1+totalsend);
	      //send ip packet
	      MinetSend(mux, outgoing_packet);

	      cs->state.SetLastSent(cs->state.GetLastSent()+bytes);
	      totalsend += bytes;
	      //update totaleft
	      totaleft -= bytes;
	    }
	  }else {//we have trie to retransmit 3 times, timeout 3 times, may be the connection is down
	    cs->bTmrActive = false;
	    SockRequestResponse reply(WRITE, cs->connection, Buffer(), 0, ECONN_FAILED);//close it
	    MinetSend(sock, reply);//close connection
	    dellist.push_back(cs);
	  }
	}
	else {//we dont have outstanding ack
	  //turn off timer
	  cs->bTmrActive = false;
	}
      }
	break;
      default:
	break;
      }
    }    
  }//end of for loop for each conn

  for(list<ConnectionList<TCPState>::iterator>::iterator it = dellist.begin(); it!=dellist.end();it++) {
    clist.erase(*it);
  }
}//end of timer event
